#include "stdafx.h"
#include "Binding.h"
#include "LocalEndPoint.h"
//#include "PortRouterClient.h"
#include "IContractChecker.h"
#include "RoomDefines.h"
#include "Portal.h"
#include "DynamicBindingManager.h"

namespace RoomFW {


ActiveObjectsBinding::ActiveObjectsBinding(IActiveObjectSP objectA, PortIndex::PrimaryIndex portA, IActiveObjectSP objectB, PortIndex::PrimaryIndex portB) :
	objectA_(objectA),
	portA_(portA),
	objectB_(objectB),
	portB_(portB)
{
	// Check for null objects.
	ASSERT(0 != objectA_);
	if (0 == objectA_)
	{
		throw std::runtime_error("objectA is null");
	}
	ASSERT(0 != objectB_);
	if (0 == objectB_)
	{
		throw std::runtime_error("objectB is null");
	}

	// Get protocols and check for null.
	IContractCheckerSPC protocolA = objectA_->getContractChecker(portA_);
	ASSERT(0 != protocolA);
	if (0 == protocolA)
	{
		throw std::runtime_error("protocolA is null");
	}
	IContractCheckerSPC protocolB = objectB_->getContractChecker(portB_);
	ASSERT(0 != protocolB);
	if (0 == protocolB)
	{
		throw std::runtime_error("protocolB is null");
	}

	// Check protocol types.
	ASSERT(protocolA->getTypeID() == protocolB->getTypeID());
	if (protocolA->getTypeID() != protocolB->getTypeID())
	{
		throw std::runtime_error("different protocol types");
	}

	// Check conjugation.
	ASSERT(protocolA->isConjugate() != protocolB->isConjugate());
	if (protocolA->isConjugate() == protocolB->isConjugate())
	{
		throw std::runtime_error("same protocol conjugation");
	}
	// Wire ports together
	IEndPointSP epA = objectA_->getEndPoint(portA);
	IEndPointSP epB = objectB_->getEndPoint(portB);
	if (!objectA_->setEndPoint(portA_, epB))
	{
		throw std::runtime_error("objectA failed to set endpoint");
	}
	if (!objectB_->setEndPoint(portB_, epA))
	{
		throw std::runtime_error("objectB failed to set endpoint");
	}
}

ActiveObjectsBinding::~ActiveObjectsBinding()
{
	// Note:  Do not throw from a destructor.  Could be in the middle of throw already...
	VERIFY(objectA_->clearEndPoint(portA_));
	VERIFY(objectB_->clearEndPoint(portB_));
}

PortalBinding::PortalBinding(PortalSP portal, IActiveObjectSP object, PortIndex::PrimaryIndex port) :
	portal_(portal)
{
	ASSERT(0 != portal);
	if (0 == portal)
	{
		throw std::runtime_error("portal is null");
	}
	PortIndex tmp(port); // Ignoring returned replication index.  What would it be used for???
	portal_->bindTo(object, tmp);
}

PortalBinding::~PortalBinding()
{
	// Note:  Do not throw from a destructor.  Could be in the middle of throw already...
	VERIFY(portal_->unbind());
}

BindingWrapper::BindingWrapper(BindingSP innerBinding) :
	innerBinding_(innerBinding)
{
}

BindingWrapper::~BindingWrapper()
{
}

void BindingWrapper::unbind()
{
	innerBinding_.reset();
}

DynamicBinding::DynamicBinding(BindingWrapperSP innerBinding) :
	innerBinding_(innerBinding)
{
}

DynamicBinding::~DynamicBinding()
{
	DynamicBindingManager::Instance().unbind(innerBinding_);
}

}
